<?php

class    PacketID
{
    const   MIN_PACKET_ID = 1;
    const   MAX_PACKET_ID = 65535;
    private static $packet_id_current = self::MAX_PACKET_ID;
    
    public static function next()
    {
        if (self::MAX_PACKET_ID == self::$packet_id_current) {
            self::$packet_id_current = self::MIN_PACKET_ID;
        }
        else {
            self::$packet_id_current += 1;
        } 
        
        return self::$packet_id_current;
    } 
}    // class PacketID 


class    Packet
{
    const REQUEST  = 'REQUEST';
    const RESPONSE = 'RESPONSE';
    
    public $action;    // REQUEST/RESPONSE
    public $service;   // service name 
    public $body;      // packet body text 
    public $packid;    // id of packet 
    public $respid;    // which one this packet response  
    
    public function __construct()
    {
        $this->action = NULL;
        $this->service = NULL;
        $this->body = NULL;
        $this->packid = 0;
        $this->respid = 0;
    }
    
    public function setRequest()
    {
        if (self::REQUEST != $this->action) {
            $this->action = self::REQUEST;
        } 
    }
    public function setResponse()
    {
        if (self::RESPONSE != $this->action) {
            $this->action = self::RESPONSE;
        } 
    }
    public function isRequest()
    {
        return (self::REQUEST == $this->action);
    }
    public function isResponse()
    {
        return (self::RESPONSE == $this->action);
    }
    
    public function isComplete() 
    {
        if (empty($this->action) || empty($this->service) || empty($this->body)) {
            return false;
        }
        
        return true;
    }
    
    function    depack($record)
    {
        $field_separator = "\t";
        $kv_separator = ':';
        $fields = split($field_separator, $record);
        foreach ($fields as $field) {
            list($k, $v) = split($kv_separator, $field, 2);
            if (empty($v)) {
                continue;
            }
            switch($k) {
            case 'action' :
                $this->action = $v;
                break;
            case 'service' :
                $this->service = $v;
                break;
            case 'packid' :
                $this->packid = $v;
                break;
            case 'respid' :
                $this->respid = $v;
                break;
            case 'body' :
                $this->body = $v;
                break;
            }
        }
        if (!$this->isComplete()) {
            return false;
        }
        
        return $this;
    }    // function depack()
    
    function    enpack()
    {
        $packid = $this->packid;
        if (empty($packid)) {
            $packid = PacketID::next();
        }
        
        $fields = array();
        $fields[] = 'action:' . $this->action;
        $fields[] = 'service:' . $this->service;
        $fields[] = 'packid:' . $packid;
        if ($this->respid > 0) {
            $fields[] = 'respid:' . $this->respid;
        }
        $fields[] = 'body:' . $this->body;
        
        $record = join("\t", $fields);
        return array($record, $packid);
    }    // function enpack()

}    // class Packet

function    depack($record)
{
    $packet = new Packet();
    
    $field_separator = "\t";
    $kv_separator = ':';
    $fields = split($field_separator, $record);
    foreach ($fields as $field) {
        list($k, $v) = split($kv_separator, $field, 2);
        if (empty($v)) {
            continue;
        }
        switch($k) {
        case 'action' :
            $packet->action = $v;
            break;
        case 'service' :
            $packet->service = $v;
            break;
        case 'packid' :
            $packet->packid = $v;
            break;
        case 'respid' :
            $packet->respid = $v;
            break;
        case 'body' :
            $packet->body = $v;
            break;
        }
    }
    if (!$packet->isComplete()) {
        return false;
    }
    
    return $packet;
}    // function depack()

function    enpack(&$packet)
{
    $packid = $packet->packid;
    if (empty($packid)) {
        $packid = PacketID::next();
    }
    
    $fields = array();
    $fields[] = 'action:' . $packet->action;
    $fields[] = 'service:' . $packet->service;
    $fields[] = 'packid:' . $packid;
    if ($packet->respid > 0) {
        $fields[] = 'respid:' . $packet->respid;
    }
    $fields[] = 'body:' . $packet->body;
    
    $record = join("\t", $fields);
    return array($record, $packid);
}    // function enpack()

